#region Using

using System;
using System.Xml;
using System.IO;
using System.Globalization;
using System.Collections.Generic;
using System.Collections.Specialized;
using BlogEngine.Core;
using BlogEngine.Core.Provider.Interfaces;

#endregion

namespace BlogEngine.Core.Provider.XML
{
	/// <summary>
	/// A storage provider for BlogEngine that uses XML files.
	/// <remarks>
	/// To build another provider, you can just copy and modify
	/// this one. Then add it to the web.config's BlogEngine section.
	/// </remarks>
	/// </summary>
	public class CIAlbums : IAlbums
	{

		/// <summary>
		/// Gets a Album based on a Guid
		/// </summary>
		/// <param name="id">The album's Guid.</param>
		/// <returns>A matching Album</returns>
		public Album Select(Guid id)
		{
			string fileName = Provider.Folder + "albums" + Path.DirectorySeparatorChar + id.ToString() + ".xml";
			Album album = new Album();
			XmlDocument doc = new XmlDocument();
			doc.Load(fileName);

			if (doc.SelectSingleNode("album/title") != null)
				album.Title = doc.SelectSingleNode("album/title").InnerText;
			if (doc.SelectSingleNode("album/author") != null)
				album.Author = doc.SelectSingleNode("album/author").InnerText;
			if (doc.SelectSingleNode("keywords") != null)
				album.Keywords = doc.Attributes["keywords"].InnerText;
			if (doc.SelectSingleNode("description") != null)
				album.Description = doc.SelectSingleNode("album/description").InnerText;
			if (doc.SelectSingleNode("slug") != null)
				album.Slug = doc.SelectSingleNode("album/slug").InnerText;
			if (doc.SelectSingleNode("ispublished") != null)
				album.IsPublished = bool.Parse(doc.SelectSingleNode("album/ispublished").InnerText);
			if (doc.SelectSingleNode("lastmodified") != null)
				album.DateModified = DateTime.Parse(doc.SelectSingleNode("lastmodified").InnerText, CultureInfo.InvariantCulture);
			else
				album.DateModified = DateTime.Now;

			album.Order = Convert.ToInt32(doc.SelectSingleNode("album/order").InnerText);

			// Tags
			foreach (XmlNode node in doc.SelectNodes("album/tags/tag"))
			{
				if (!string.IsNullOrEmpty(node.InnerText))
					album.Tags.Add(node.InnerText);
			}

			// comments
			foreach (XmlNode node in doc.SelectNodes("album/comments/comment"))
			{
				Comment comment = new Comment();
				comment.Id = new Guid(node.Attributes["id"].InnerText);
				comment.Author = node.SelectSingleNode("author").InnerText;
				comment.Email = node.SelectSingleNode("email").InnerText;
				comment.Parent = album;

				if (node.SelectSingleNode("country") != null)
					comment.Country = node.SelectSingleNode("country").InnerText;

				if (node.SelectSingleNode("ip") != null)
					comment.IP = node.SelectSingleNode("ip").InnerText;

				if (node.SelectSingleNode("website") != null)
				{
					Uri website;
					if (Uri.TryCreate(node.SelectSingleNode("website").InnerText, UriKind.Absolute, out website))
						comment.Website = website;
				}

				if (node.Attributes["approved"] != null)
					comment.IsApproved = bool.Parse(node.Attributes["approved"].InnerText);
				else
					comment.IsApproved = true;

				comment.Content = node.SelectSingleNode("content").InnerText;
				comment.DateCreated = DateTime.Parse(node.SelectSingleNode("date").InnerText, CultureInfo.InvariantCulture);

				album.Comments.Add(comment);
			}

			album.Comments.Sort();

			// photo effects
			foreach (XmlNode node2 in doc.SelectNodes("album/photoeffects/photoeffect"))
			{
				Guid key = new Guid(node2.InnerText);
				PhotoEffect photoeffect = PhotoEffect.GetById(key);
				if (photoeffect != null)
					album.PhotoEffects.Add(photoeffect);
			}
			return album;
		}

		/// <summary>
		/// Inserts an Album
		/// </summary>
		/// <param name="album">Must be a valid Album object.</param>
		public void Insert(Album album)
		{
			if (!Directory.Exists(Provider.Folder + "albums"))
				Directory.CreateDirectory(Provider.Folder + "albums");

			string fileName = Provider.Folder + "albums" + Path.DirectorySeparatorChar + album.Id.ToString() + ".xml";
			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;

			using (XmlWriter writer = XmlWriter.Create(fileName, settings))
			{
				writer.WriteStartDocument(true);

				writer.WriteStartElement("album");
				writer.WriteAttributeString("id", album.Id.ToString());
				writer.WriteElementString("title", album.Title);
				writer.WriteElementString("slug", album.Slug);
				writer.WriteElementString("keywords", album.Keywords.ToString());
				writer.WriteElementString("description", album.Description);
				writer.WriteElementString("ispublished", album.IsPublished.ToString());
				writer.WriteElementString("order", album.Order.ToString());
				writer.WriteElementString("lastmodified", album.DateModified.AddHours(-BlogSettings.Instance.Timezone).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));

				// tags
				writer.WriteStartElement("tags");
				foreach (string tag in album.Tags)
					writer.WriteElementString("tag", tag);
				writer.WriteEndElement();

				// comments
				writer.WriteStartElement("comments");
				foreach (Comment comment in album.Comments)
				{
					writer.WriteStartElement("comment");
					writer.WriteAttributeString("id", comment.Id.ToString());
					writer.WriteAttributeString("approved", comment.IsApproved.ToString());
					writer.WriteElementString("date", comment.DateCreated.AddHours(-BlogSettings.Instance.Timezone).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
					writer.WriteElementString("author", comment.Author);
					writer.WriteElementString("email", comment.Email);
					writer.WriteElementString("country", comment.Country);
					writer.WriteElementString("ip", comment.IP);
					if (comment.Website != null)
						writer.WriteElementString("website", comment.Website.ToString());
					writer.WriteElementString("content", comment.Content);
					writer.WriteEndElement();
				}
				writer.WriteEndElement();

				// photo effects
				writer.WriteStartElement("photoeffects");
				foreach (PhotoEffect photoeffect in album.PhotoEffects)
					writer.WriteElementString("photoeffect", photoeffect.Id.ToString());
				writer.WriteEndElement();

				writer.WriteEndElement();
			}

			if (!Album.Items.Contains(album))
				Album.Items.Add(album);

			Album.Items.Sort();
		}

		/// <summary>
		/// Updates an Album
		/// </summary>
		/// <param name="album">Must be a valid Album object.</param>
		public void Update(Album album)
		{
			Insert(album);
		}

		/// <summary>
		/// Deletes a Album
		/// </summary>
		/// <param name="album">Must be a valid Album object.</param>
		public void Delete(Album album)
		{
			if (Album.Items.Contains(album))
				Album.Items.Remove(album);

			string fileName = Provider.Folder + "albums" + Path.DirectorySeparatorChar + album.Id.ToString() + ".xml";
			if (File.Exists(fileName))
				File.Delete(fileName);
		}

		/// <summary>
		/// Fills an unsorted list of albums.
		/// </summary>
		/// <returns>A List&lt;Album&gt; of all Albums.</returns>
		public List<Album> Fill()
		{
			string folder = Provider.Folder + "albums" + Path.DirectorySeparatorChar;
			List<Album> albums = new List<Album>();

			foreach (string file in Directory.GetFiles(folder, "*.xml", SearchOption.TopDirectoryOnly))
			{
				FileInfo info = new FileInfo(file);
				string id = info.Name.Replace(".xml", string.Empty);
				Album album = Album.Load(new Guid(id));
				albums.Add(album);
			}

			albums.Sort();
			return albums;
		}
	}
}
